import uuid

from sqlalchemy.dialects.mysql import LONGTEXT

from app.models import BaseModel
from app.models.userModel import User
from tools import db
from utils.enums import TextChoices
from tools.basic_tools import Tools


def gen_id():
    return uuid.uuid4()


class LinkType(TextChoices):
    ctf = "ctf", "ctf比赛"
    ctf_red_blue = "ctf_red_blue", "红蓝对抗赛"
    courseware = "courseware", "课件"


class Range(db.Model, BaseModel):

    # 仅内置场景类型
    class RangeTemplate(TextChoices):
        tobacco = "tobacco", "烟草场景"
        wind_power = "wind_power", "风力发电场景"
        traffic_signals = "traffic_signals", "交通场景"
        nuclear_power = "nuclear_power", "核能发电场景"
        steel_making = "steel_making", "炼钢场景"
        petroleum = "petroleum", "石油石化场景"
        granulation = "granulation", "中药制粒场景"
        canning = "canning", "中药罐装场景"
        concentrate = "concentrate", "中药提取浓缩场景"
        intelligent_make = "intelligent_make", "智能制造场景"
        hydro_power_1 = "hydro_power_1", "水力发电场景1"
        hydro_power_2 = "hydro_power_2", "水力发电场景2"
        water_system = "water_system", "水务系统场景"
        thermal_power_1 = "thermal_power_1", "火力发电场景1"
        thermal_power_2 = "thermal_power_2", "火力发电场景2"
        brand_controller_1 = "brand_controller_1", "多品牌控制器组合场景1"
        brand_controller_2 = "brand_controller_2", "多品牌控制器组合场景2"
        brand_controller_iFIX = "brand_controller_iFIX", "多品牌控制器iFIX组合场景"
        wind_power_2 = "wind_power_2", "风力发电场景2"
        pv_power = "pv_power", "光伏发电场景"
        nuclear_power_2 = "nuclear_power_2", "核能发电场景2"
        heat_exchange = "heat_exchange", "换热站场景"

    __tablename__ = "api_range"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(120), index=True)
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    # 难易程度 1,2,3   容易->难
    difficulty = db.Column(db.Integer, default=1)
    start = db.Column(db.Integer, default=0)
    topology_json = db.Column(LONGTEXT)
    topology_img = db.Column(LONGTEXT)
    is_system = db.Column(db.Boolean, index=True, default=0)
    # 简介
    describe = db.Column(db.TEXT, default=None)
    vmNum = db.Column(db.Integer, index=True, default=0)
    rangeVmList = db.relationship(
        "RangeLinkModule", backref="Range", uselist=True, cascade="all, delete-orphan"
    )
    # 靶场模板类型，参考 Range.RangeTemplate，为拓展不使用enum类型
    range_template_type = db.Column(
        db.String(50), default="", nullable=False, comment="模版类型，用于渲染3D模型"
    )
    is_public = db.Column(
        db.Boolean, default=0, comment="是否公共靶场", doc="不受user_id限制，允许所有用户查看操纵"
    )
    is_draft = db.Column(
        db.Boolean, default=0, comment="是否草稿状态", doc="拓扑页面未点击确定按钮时均为草稿状态"
    )

    def to_dict(self):
        return {
            "id": self.id,
            "name": self.name,
            "user_id": self.user_id,
            "difficulty": self.difficulty,
            "start": self.start,
            "topology_json": self.topology_json,
            "topology_img": self.topology_img,
            "is_system": self.is_system,
            "describe": self.describe,
            "vmNum": self.vmNum,
            "rangeVmList": [_.to_dict() for _ in self.rangeVmList]
        }


class RangeLinkModule(db.Model, BaseModel):
    __tablename__ = "api_range_module"  # 关联其他模块表
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    range_id = db.Column(db.Integer, db.ForeignKey(Range.id, ondelete="CASCADE"))
    # type = db.Column(
    #     # 1: 任务 2：课件 3：ctf
    #     db.Enum('1', '2', '3'),
    #     server_default='1',
    #     nullable=False,
    #     index=True)
    range_uuid = db.Column(db.String(40), default=gen_id, unique=True)
    task_id = db.Column(db.Integer)
    courseware_id = db.Column(db.Integer)
    ctf_id = db.Column(db.String(11), unique=True)
    user_id = db.Column(db.Integer)
    network_id = db.Column(db.String(32), index=True)
    rangeInfo = db.relationship("Range", uselist=True, backref="Range")
    vmList = db.relationship(
        "RangeVm", backref="RangeLinkModule", uselist=True, cascade="all, delete-orphan"
    )
    router_set = db.relationship("RangeRouter", backref="range_router", lazy="dynamic")
    vxlan_pool_id = db.Column(db.String(32), default="", nullable=True, comment="vxlan_pool的uuid")
    clone_range_uuid = db.Column(db.String(40))

    def to_dict(self):
        return {
            "id": self.id,
            "range_id": self.range_id,
            "range_uuid": self.range_uuid,
            "task_id": self.task_id,
            "courseware_id": self.courseware_id,
            "ctf_id": self.ctf_id,
            "user_id": self.user_id,
            "network_id": self.network_id,
            "vmList": [_.to_dict() for _ in self.vmList],
            "router_set": [_.to_dict() for _ in self.router_set.all()],
            "vxlan_pool_id": self.vxlan_pool_id,
            "clone_range_uuid": self.clone_range_uuid
        }


class VmType(TextChoices):
    vm = "vm", "虚拟机"
    route = "route", "路由"
    firewall = "firewall", "防火墙"
    audit = "audit", "审计"
    plc_smz = "plc-smz", "西门子plc"
    plc_ab = "plc-ab", "ab plc"
    plc_snd = "plc-snd", "施耐德plc"
    plc_other = "plc-other", "其他plc"
    scan = "scan", "漏扫"
    attack = "attack", "攻击平台"
    wincc = "wincc", "wincc"
    scada_ifix = "scada-ifix", "scada-ifix"
    mis = "mis", "mis"
    plc_omron = "plc-omron", "欧姆龙pLC"
    plc_sanling = "plc-sanling", "三菱plc"
    plc_taida = "plc-taida", "台达"
    scada_yk = "scada-yk", "亚控"
    scada_ge = "scada-ge", "GE"
    scada_lk = "scada-lk", "力控"
    scada_snd = "scada-snd", "施耐德"
    scada_jk = "scada-jk", "杰控"
    HIDS = "HIDS", "wazuh"
    NIDS = "NIDS", "suricata"
    vpn = "vpn", "vpn"
    sensor = "sensor", "传感器"
    sis = "sis", "sis数据库"
    ifix = "ifix", "ifix"
    vs = "vs", "虚拟仿真"
    self = "self", "自用"
    mysql = "mysql", "mysql"
    redis = "redis", "redis"
    frg = "frg", "流量发生器"
    container = "container", "容器"


class RangeVm(db.Model, BaseModel):
    __tablename__ = "api_range_vm"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    range_uuid = db.Column(
        db.String(40), db.ForeignKey(RangeLinkModule.range_uuid, ondelete="CASCADE")
    )
    vm_uuid = db.Column(db.String(40), default=gen_id, unique=True)
    vm_name = db.Column(db.String(130))
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    op_vm_uuid = db.Column(db.String(130))
    op_vm_name = db.Column(db.String(130), comment="实例唯一名称")
    flavor = db.Column(db.String(130))
    image = db.Column(db.String(130))
    subnet_id = db.Column(db.String(120))
    image_snapshot = db.Column(db.String(130))
    status = db.Column(db.Integer, index=True)
    v4_fixed_ip = db.Column(db.String(50))
    external_ip = db.Column(db.String(50))
    is_external = db.Column(db.Integer, default=0, index=True)
    eip_uuid = db.Column(db.String(50), default="", comment="external_ip的唯一id")
    type = db.Column(
        db.Enum(*VmType.values),
        server_default="vm",
        nullable=False,
        index=True,
    )
    # deleted = db.Column(db.Integer, index=True,default=0)   # 1代表.删除
    security_group_set = db.relationship("SecGroup", backref="rangeVm", lazy="dynamic")
    flag_3d_mark = db.Column(
        db.String(30),
        nullable=True,
        index=True,
        comment="3D大屏展示标志",
        doc="用于标记哪个模型需要展示攻击效果",
    )

    user = db.relationship("User", uselist=False)
    state = db.Column(db.Integer, default=0)

    def to_dict(self):
        return {
            "range_uuid": self.range_uuid,
            "vm_name": self.vm_name,
            "vm_uuid": self.vm_uuid,
            "user_id": self.user_id,
            "op_vm_uuid": self.op_vm_uuid,
            "op_vm_name": self.op_vm_name,
            "id": self.id,
            "flavor": self.flavor,
            "image": self.image,
            "status": self.status,
            "v4_fixed_ip": self.v4_fixed_ip,
            "external_ip": self.external_ip,
            "is_external": self.is_external,
            "type": self.type,
            "subnet_id": self.subnet_id,
            "security_group_set": [_.to_dict() for _ in self.security_group_set],
            "eip_uuid": self.eip_uuid
        }


class ActiveRangeStatus(TextChoices):
    building = "BUILDING", "构建中"
    active = "ACTIVE", "活动"
    error = "ERROR", "错误"


class ActiveRange(db.Model, BaseModel):
    __tablename__ = "api_active_range"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    range_uuid = db.Column(
        db.String(40),
        db.ForeignKey(RangeLinkModule.range_uuid, ondelete="CASCADE"),
        index=True,
    )
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    status = db.Column(db.Enum("BUILDING", "ACTIVE", "ERROR"), index=True)
    activeRange_range_uuid = db.Column(db.String(40), default=gen_id, unique=True)
    activeRangeVmList = db.relationship(
        "ActiveRangeVm",
        backref="ActiveRange",
        uselist=True,
        cascade="all, delete-orphan",
    )
    network_id = db.Column(db.String(40))


class ActiveRangeVm(db.Model, BaseModel):
    __tablename__ = "api_active_range_vm"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    range_uuid = db.Column(db.String(40), index=True)
    new_vm_uuid = db.Column(db.String(40), default=gen_id, unique=True)
    name = db.Column(db.String(130))
    op_vm_uuid = db.Column(db.String(130))
    flavor = db.Column(db.String(130))
    image = db.Column(db.String(130))
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    v4_fixed_ip = db.Column(db.String(50))
    is_external = db.Column(db.Integer, default=0, index=True)
    external_ip = db.Column(db.String(50))
    status = db.Column(db.String(20))
    activeRange_range_uuid = db.Column(
        db.String(40),
        db.ForeignKey(ActiveRange.activeRange_range_uuid, ondelete="CASCADE"),
    )
    subnet_id = db.Column(db.String(120))
    type = db.Column(
        db.Enum(*VmType.values),
        server_default="vm",
        nullable=False,
        index=True,
    )
    user = db.relationship("User", uselist=False)
    eip_uuid = db.Column(db.String(50), default="", comment="external_ip的唯一id")


class SecGroup(db.Model, BaseModel):
    __tablename__ = "sec_group"
    id = db.Column(db.Integer, primary_key=True)
    group_id = db.Column(db.String(40), unique=True)
    range_vm_uuid = db.Column(
        db.String(40),
        db.ForeignKey("api_range_vm.vm_uuid", ondelete="CASCADE", onupdate="CASCADE"),
    )


class RangeRouter(db.Model, BaseModel):
    __tablename__ = "api_range_router"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    router_uuid = db.Column(db.String(40), default=gen_id, unique=True)
    router_name = db.Column(db.String(130))
    status = db.Column(db.Enum("0", "1", "2"), default="0")
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    range_uuid = db.Column(
        db.String(40), db.ForeignKey(RangeLinkModule.range_uuid, ondelete="CASCADE")
    )
    encrypt_config_set = db.relationship(
        "EncryptConfig", backref="range_router", lazy="dynamic"
    )
    gatekeeper_set = db.relationship(
        "Gatekeeper", backref="range_router", lazy="dynamic"
    )

    def to_dict(self):
        return {
            "id": self.id,
            "router_uuid": self.router_uuid,
            "router_name": self.router_name,
            "status": self.status,
            "encrypt_config_set": [
                _.to_dict() for _ in self.encrypt_config_set.all()
            ],
            "gatekeeper_set": [_.to_dict() for _ in self.gatekeeper_set.all()],
        }


class EncryptConfig(db.Model, BaseModel):
    __tablename__ = "api_encrypt_config"
    id = db.Column(db.Integer, primary_key=True)
    gateway_name = db.Column(db.String(130))
    gateway_address = db.Column(db.String(20))
    remote_address = db.Column(db.String(20))
    system_type = db.Column(db.Enum("装置管理", "日志审计", "远程调试"), default="装置管理")
    certificate = db.Column(
        db.Enum("一级CA证书", "二级CA证书", "主操作员证书", "备操作员证书", "装置管理系统证书"), default="一级CA证书"
    )

    router_uuid = db.Column(
        db.String(40),
        db.ForeignKey(
            "api_range_router.router_uuid", ondelete="CASCADE", onupdate="CASCADE"
        ),
    )
    strategy_set = db.relationship(
        "StrategyConfig", backref="encrypt_config", lazy="dynamic"
    )

    def to_dict(self):
        return {
            "id": self.id,
            "gateway_name": self.gateway_name,
            "gateway_address": self.gateway_address,
            "remote_address": self.remote_address,
            "system_type": self.system_type,
            "certificate": self.certificate,
            "router_uuid": self.router_uuid,
            "strategy_set": [_.to_dict() for _ in self.strategy_set.all()],
        }


class StrategyConfig(db.Model, BaseModel):
    __tablename__ = "api_strategy_config"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(130))
    ether_type = db.Column(db.Enum("TCP", "UDP"), default="TCP")
    in_start_address = db.Column(db.String(20))
    in_end_address = db.Column(db.String(20))
    ex_start_address = db.Column(db.String(20))
    ex_end_address = db.Column(db.String(20))
    in_port_range_max = db.Column(db.Integer)
    in_port_range_min = db.Column(db.Integer)
    ex_port_range_max = db.Column(db.Integer)
    ex_port_range_min = db.Column(db.Integer)

    encrypt_id = db.Column(
        db.Integer,
        db.ForeignKey("api_encrypt_config.id", ondelete="CASCADE", onupdate="CASCADE"),
    )

    def to_dict(self):
        return {
            "id": self.id,
            "name": self.name,
            "ether_type": self.ether_type,
            "in_start_address": self.in_start_address,
            "in_end_address": self.in_end_address,
            "ex_start_address": self.ex_start_address,
            "ex_end_address": self.ex_end_address,
            "in_port_range_max": self.in_port_range_max,
            "in_port_range_min": self.in_port_range_min,
            "ex_port_range_max": self.ex_port_range_max,
            "ex_port_range_min": self.ex_port_range_min,
            "encrypt_id": self.encrypt_id,
        }


class Gatekeeper(db.Model, BaseModel):
    __tablename__ = "api_gatekeeper"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(130))
    description = db.Column(db.TEXT, default=None)

    router_uuid = db.Column(
        db.String(40),
        db.ForeignKey(
            "api_range_router.router_uuid", ondelete="CASCADE", onupdate="CASCADE"
        ),
    )
    gatekeeper_rule_set = db.relationship(
        "GatekeeperRule", backref="gatekeeper", lazy="dynamic"
    )

    def to_dict(self):
        return {
            "id": self.id,
            "name": self.name,
            "description": self.description,
            "router_uuid": self.router_uuid,
            "gatekeeper_rule_set": [
                _.to_dict() for _ in self.gatekeeper_rule_set.all()
            ],
        }


class GatekeeperRule(db.Model, BaseModel):
    __tablename__ = "api_gatekeeper_rule"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(130))
    ether_type = db.Column(db.Enum("TCP", "UDP"), default="TCP")
    in_real_address = db.Column(db.String(20))
    in_virtual_address = db.Column(db.String(20))
    in_virtual_mask = db.Column(db.String(20))
    in_port_range_min = db.Column(db.Integer)
    in_port_range_max = db.Column(db.Integer)
    in_gateway_address = db.Column(db.String(20))
    ex_real_address = db.Column(db.String(20))
    ex_virtual_address = db.Column(db.String(20))
    ex_virtual_mask = db.Column(db.String(20))
    ex_port_range_min = db.Column(db.Integer)
    ex_port_range_max = db.Column(db.Integer)
    ex_gateway_address = db.Column(db.String(20))

    gatekeeper_id = db.Column(
        db.Integer,
        db.ForeignKey("api_gatekeeper.id", ondelete="CASCADE", onupdate="CASCADE"),
    )

    def to_dict(self):
        return {
            "id": self.id,
            "name": self.name,
            "ether_type": self.ether_type,
            "in_real_address": self.in_real_address,
            "in_virtual_address": self.in_virtual_address,
            "in_virtual_mask": self.in_virtual_mask,
            "in_port_range_min": self.in_port_range_min,
            "in_port_range_max": self.ex_port_range_max,
            "in_gateway_address": self.in_gateway_address,
            "ex_real_address": self.in_real_address,
            "ex_virtual_address": self.in_virtual_address,
            "ex_virtual_mask": self.in_virtual_mask,
            "ex_port_range_min": self.in_port_range_min,
            "ex_port_range_max": self.ex_port_range_max,
            "ex_gateway_address": self.in_gateway_address,
            "gatekeeper_id": self.gatekeeper_id,
        }


class WebHook(db.Model, BaseModel):
    __tablename__ = "api_web_hook"
    id = db.Column(db.Integer, primary_key=True)
    resource_uuid = db.Column(db.String(50))
    job_uuid = db.Column(db.String(50))
    action = db.Column(db.String(255))
    follow_up = db.Column(db.String(20))
    state = db.Column(db.Integer, default=0)
    request_params = db.Column(db.String(1000))
    
    def to_dict(self):
        return {
            "id": self.id,
            "resource_uuid": self.resource_uuid,
            "job_uuid": self.job_uuid,
            "action": self.action,
            "follow_up": self.follow_up,
            "state": self.state,
            "request_params": self.request_params,
        }


class WebHookJob(db.Model, BaseModel):
    __tablename__ = 'api_webhook'
    id = db.Column(db.Integer, primary_key=True)
    range_uuid = db.Column(db.String(50), comment="场景id")
    work_uuid = db.Column(db.String(50), comment="事务id")
    job_uuid = db.Column(db.String(50), unique=True, comment="每一个请求唯一标识id")
    action = db.Column(db.String(50), comment="行为动作")
    request_params = db.Column(db.JSON, comment="请求参数")
    result = db.Column(db.JSON, comment="结果")
    state = db.Column(db.Integer, default=0, comment="状态: 0 初始化, 1: 执行中 2: 成功  3: 失败, 4: 回滚 5: 回滚完成")
    message_state = db.Column(db.Integer, default=1, comment="消息通知, 1 通知，0 不通知")
    message_uuid = db.Column(db.String(50), comment="消息唯一值，与websocke 通信")
    faild_message =  db.Column(db.JSON, comment="失败的消息, 可为空， 空则使用配置文件的")

    def to_dict(self):
        return {
            "id": self.id,
            "range_uuid": self.range_uuid,
            "work_uuid": self.work_uuid,
            "job_uuid": self.job_uuid,
            "action": self.action,
            "request_params": self.request_params,
            "result": self.result,
            "state": self.state,
            "message_state": self.message_state,
            "message_uuid": self.message_uuid,
            "faild_message": self.faild_message
        }
        
        

class RangeVni(db.Model, BaseModel):
    """记录场景vni"""
    __tablename__ = "api_range_vni"
    id = db.Column(db.Integer, primary_key=True)
    start_vni = db.Column(db.Integer, default=0)
    end_vni = db.Column(db.Integer, default=0)
    pool_uuid = db.Column(db.String(40))
    
    def to_dict(self):
        return {
            "id": self.id,
            "start_vni": self.start_vni,
            "end_vni": self.end_vni,
            "pool_uuid": self.pool_uuid
        }
        
        
class SecurityGroup(db.Model, BaseModel):
    """记录安全组信息"""
    __tablename__ = "api_security_group"
    id = db.Column(db.Integer, primary_key=True)
    security_group_name = db.Column(db.String(20))
    security_group_uuid = db.Column(db.String(40), index=True)
    range_uuid = db.Column(
        db.String(40), db.ForeignKey(RangeLinkModule.range_uuid, ondelete="CASCADE")
    )
    description = db.Column(db.String(255))
    def to_dict(self):
        return {
            "id": self.id,
            "security_group_name": self.security_group_name,
            "security_group_uuid": self.security_group_uuid,
            "range_uuid": self.range_uuid,
            "description": self.description
        }
        
class SecurityGroupAssociate(db.Model, BaseModel):
    """安全组关联信息"""
    __tablename__ = "api_security_group_associate"
    id = db.Column(db.Integer, primary_key=True)
    vm_uuid = db.Column(db.String(40))
    vm_nic_uuid = db.Column(db.String(40))
    security_group_uuid = db.Column(
        db.String(40), db.ForeignKey(SecurityGroup.security_group_uuid, ondelete="CASCADE")
    )
    range_uuid = db.Column(
        db.String(40), db.ForeignKey(RangeLinkModule.range_uuid, ondelete="CASCADE")
    )
    
    def to_dict(self):
        return {
            "id": self.id,
            "security_group_uuid": self.security_group_uuid,
            "vm_uuid": self.vm_uuid,
            "vm_nic_uuid": self.vm_nic_uuid,
            "range_uuid": self.range_uuid
        }
    
    
class StackTemplate(db.Model, BaseModel):
    """资源栈模板"""
    __tablename__ = "api_stack_template"
    
    id = db.Column(db.Integer, primary_key=True)
    stack_name = db.Column(db.String(40))
    stack_uuid = db.Column(db.String(40), index=True)
    range_uuid = db.Column(
        db.String(40), db.ForeignKey(RangeLinkModule.range_uuid, ondelete="CASCADE")
    )
    template_content = db.Column(db.String(1000))
    is_system = db.Column(db.Enum("0", "1", "2"),  nullable=False, default="0", comment="0: 比赛  1 课程")
    def to_dict(self):
        return {
            "id": self.id,
            "stack_uuid": self.stack_uuid,
            "range_uuid": self.range_uuid,
            "template_content": self.template_content,
            "stack_name": self.stack_name,
            "is_system": self.is_system
        }


class StackResource(db.Model,BaseModel):
    """学生资源"""
    __tablename__ = "api_stack_resource"
    id = db.Column(db.Integer, primary_key=True)
    resource_stack_uuid = db.Column(db.String(40))
    resource_stack_name = db.Column(db.String(40))
    range_uuid = db.Column(
        db.String(40), db.ForeignKey(RangeLinkModule.range_uuid, ondelete="CASCADE")
    )
    user_id = db.Column(
        db.Integer, db.ForeignKey(User.id, ondelete="CASCADE")
    )
    stack_uuid = db.Column(
        db.String(40), db.ForeignKey(StackTemplate.stack_uuid, ondelete="CASCADE")
    )
    
